// 左侧输入框的值分割变更为字符串数组
export function leftTextToStrArr(that) {
    if (that.leftText === '') {
        that.$message.error('请输入要转换的列')
        return
    }
    // 先确保都是\n 好分割
    that.leftText = that.leftText.replaceAll('\r\n', '\n').replaceAll('\r', '\n')
    // 获取分割字符串
    if (that.separator !== '') {
        that.leftText = that.leftText.replaceAll(that.separator, '\n')
    }
    that.leftText = that.leftText.replaceAll('\n\n', '\n')
    let splitArr = that.leftText.split('\n')
    return splitArr.filter((item) => {
        return item !== '' && item !== ','
    }).map((item) => {
        return item.trim()
    })
}

export function delLastComma(str) {
    if (str == null || str === '' || str === undefined) {
        return ''
    }
    return str.substr(0, str.lastIndexOf(','))
}

export async function copy2Clipboard(that) {
    try {
        await navigator.clipboard.writeText(that.rightText);
        that.$message.success('复制成功');
    } catch (err) {
        that.$message.error(`复制失败${err}`);
    }
}

export function toCamelCase(column) {
    return column.replace(/_([a-z])/g, function (match, letter) {
        return letter.toUpperCase();
    });
}

export function getForeachStr(that) {
    that.leftText = that.leftText.replace('(', '').replace(')', '')
    // 分割字符串
    const splitArr = leftTextToStrArr(that)
    let resultStr = ''
    if (splitArr.length === 1) {
        resultStr = `${that.outForeachPrefix}\t#{item}${that.suffix}`
    } else {
        resultStr = `${that.inForeachPrefix}(\n${getForeachItemStr(splitArr)}\n)${that.suffix}`
    }
    return resultStr
}

export function getForeachItemStr(splitArr) {
    let resultStr = ''
    splitArr.map((item => {
        resultStr += `\t#{item.${toCamelCase(item)}},\n`
    }))
    resultStr = `${delLastComma(resultStr)}`
    return resultStr
}

export function strIsBlank(str) {
    return str === '' || str === null || str === undefined
}

/**
 * 驼峰首字母大写
 * @param str
 */
export function camelCaseFirstChar2Upper(str) {
    if (str.indexOf('_') !== -1) {
        str = toCamelCase(str)
    }
    let arr = str.split('')
    arr[0] = arr[0].toUpperCase()
    return arr.join('')
}

export function camelCaseFirstChar2Lower(str) {
    if (str.indexOf('_') !== -1) {
        str = toCamelCase(str)
    }
    let arr = str.split('')
    arr[0] = arr[0].toLowerCase()
    return arr.join('')
}

export function convertTableInfo(tableInfo, config, dbType) {
    //=========处理字段============
    const columns = tableInfo.columns
    let columnList = []
    initTypeMapping()
    const typeMapping = JSON.parse(localStorage.getItem(dbType))
    for (const item of columns) {
        columnList.push(convertColumn(config, typeMapping, item))
    }
    let primaryKey = tableInfo.primaryKey
    if (tableInfo.primaryKey) {
        const arr = columnList.filter(item => item.name === primaryKey)
        if (arr.length > 0) {
            primaryKey = arr[0]
        }
    } else {
        primaryKey = columnList[0]
    }
    //=========处理字段============
    let tableName = tableInfo.tableName
    if (config.tablePrefix) {
        tableName = tableName.replace(config.tablePrefix, '')
    }
    const table = {
        tableName: tableInfo.tableName,
        className: camelCaseFirstChar2Upper(tableName),
        firstLowerClassName: camelCaseFirstChar2Lower(tableName),
        tableComment: tableInfo.tableComment,
    }
    const simpleSuperClass = config.superClass.split('.')
    if (config.basePackage && !config.basePackage.endsWith('.')) {
        config.basePackage += '.'
    }
    config.date = formatDate(new Date())
    return {
        table,
        primaryKey,
        columnList,
        config,
        simpleSuperClass: simpleSuperClass[simpleSuperClass.length - 1]
    }
}

export function formatDate(date) {
    const year = date.getFullYear();
    const month = String(date.getMonth() + 1).padStart(2, '0');
    const day = String(date.getDate()).padStart(2, '0');
    const hours = String(date.getHours()).padStart(2, '0');
    const minutes = String(date.getMinutes()).padStart(2, '0');
    const seconds = String(date.getSeconds()).padStart(2, '0');

    return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
}

/**
 * 处理entity需要引入的列
 * @param config        配置信息
 */
export function getEntityImportList(config) {
    let resultArr = []
    if (config.lombok) {
        resultArr.push('lombok.Data')
        if (config.superClass) {
            resultArr.push(`${config.superClass}`)
        }
        resultArr.push('lombok.experimental.Accessors')
    }
    if (config.dateType === 'LocalDateTime') {
        resultArr.push('java.time.LocalDateTime')
    }
    if (config.dateType === 'LocalDate') {
        resultArr.push('java.time.LocalDate')
    }
    if (config.dateType === 'LocalTime') {
        resultArr.push('java.time.LocalTime')
    }
    if (config.dateType === 'Date') {
        resultArr.push('java.util.Date')
    }
    if (config.dateType === 'Timestamp') {
        resultArr.push('java.sql.Timestamp')
    }
    if (config.superClass) {
        resultArr.push(config.superClass)
    }
    if (config.swagger === 'knife4j') {
        resultArr.push('io.swagger.annotations.ApiModel')
        resultArr.push('io.swagger.annotations.ApiModelProperty')
    }
    if (config.page === 'mybatisPage') {
        resultArr.push('com.baomidou.mybatisplus.extension.plugins.pagination.PageDTO')
    }
    return resultArr
}

/**
 * 处理字段
 * @param config        配置信息
 * @param typeList      类型映射
 * @param col           字段
 * @returns {{field, camelCaseField: *, name, comment: *, type, javaType: string}}
 */
export function convertColumn(config, typeList, col) {
    // 默认类型为String
    let javaType = "String"
    // 如果数据库定义的类型以配置的xxx开头，则设置为对应的类型
    typeList.map(item => {
        if (col.type.toUpperCase().startsWith(item.startWith.toUpperCase())) {
            javaType = item.javaType
        }
    })
    // 对于时间类型的，选用用户配置信息
    const dateTypes = ['LocalDateTime', 'LocalDate', 'Date', 'Timestamp'];
    const dateCol = dateTypes.includes(javaType);
    if (dateCol) {
        javaType = config.dateType
    }
    let afterName = col.name
    if (config.fieldPrefix) {
        afterName = afterName.replace(config.fieldPrefix, '')
    }
    return {
        name: col.name,
        field: toCamelCase(afterName),
        camelCaseField: camelCaseFirstChar2Upper(afterName),
        type: col.type,
        dateCol,
        comment: col.comment.replaceAll('\'', ''),
        javaType
    }
}


export function initTypeMapping() {

    const mysqlMapping = [
        {
            "typeReg": "int\\w+",
            "startWith": "int",
            "javaType": "Integer"
        },
        {
            "typeReg": "varchar(\\d+)",
            "startWith": "varchar",
            "javaType": "String"
        },
        {
            "typeReg": "char(\\d+)",
            "startWith": "char",
            "javaType": "String"
        },
        {
            "typeReg": "float\\w+",
            "startWith": "float",
            "javaType": "Float"
        },
        {
            "typeReg": "double\\w+",
            "startWith": "double",
            "javaType": "Double"
        },
        {
            "typeReg": "date",
            "startWith": "date",
            "javaType": "Date"
        },
        {
            "typeReg": "datetime",
            "startWith": "datetime",
            "javaType": "Timestamp"
        },
        {
            "typeReg": "tinyint",
            "startWith": "tinyint",
            "javaType": "Byte"
        },
        {
            "typeReg": "smallint",
            "startWith": "smallint",
            "javaType": "Short"
        },
        {
            "typeReg": "bigint",
            "startWith": "bigint",
            "javaType": "Long"
        }
    ];
    const oracleMapping = [
        {
            "typeReg": "NUMBER\\((\\d+),\\d+\\)",
            "startWith": "NUMBER",
            "javaType": "BigDecimal"
        },
        {
            "typeReg": "NUMBER\\(\\d+\\)",
            "startWith": "NUMBER",
            "javaType": "Long"
        },
        {
            "typeReg": "VARCHAR2(\\d+)",
            "startWith": "VARCHAR2",
            "javaType": "String"
        },
        {
            "typeReg": "CHAR(\\d+)",
            "startWith": "CHAR",
            "javaType": "String"
        },
        {
            "typeReg": "DATE",
            "startWith": "DATE",
            "javaType": "Date"
        },
        {
            "typeReg": "TIMESTAMP",
            "startWith": "TIMESTAMP",
            "javaType": "Timestamp"
        },
        {
            "typeReg": "CLOB",
            "startWith": "CLOB",
            "javaType": "Clob"
        },
        {
            "typeReg": "BLOB",
            "startWith": "BLOB",
            "javaType": "Blob"
        }
    ];
    const pgSqlMapping = [
        {
            "typeReg": "integer",
            "startWith": "integer",
            "javaType": "Integer"
        },
        {
            "typeReg": "bigint",
            "startWith": "bigint",
            "javaType": "Long"
        },
        {
            "typeReg": "varchar(\\d+)",
            "startWith": "varchar",
            "javaType": "String"
        },
        {
            "typeReg": "char(\\d+)",
            "startWith": "char",
            "javaType": "String"
        },
        {
            "typeReg": "float\\d+",
            "startWith": "float",
            "javaType": "Float"
        },
        {
            "typeReg": "double precision",
            "startWith": "double",
            "javaType": "Double"
        },
        {
            "typeReg": "date",
            "startWith": "date",
            "javaType": "Date"
        },
        {
            "typeReg": "timestamp",
            "startWith": "timestamp",
            "javaType": "Timestamp"
        },
        {
            "typeReg": "text",
            "startWith": "text",
            "javaType": "String"
        }
    ]

    localStorage.setItem("mysql", JSON.stringify(mysqlMapping))
    localStorage.setItem("oracle", JSON.stringify(oracleMapping))
    localStorage.setItem("postgresql", JSON.stringify(pgSqlMapping))
}

export function getXmlData(afterConvert, dbType, prefix, suffix) {
    const primaryKey = afterConvert.primaryKey.name
    const columnList = afterConvert.columnList
    const resultMap = []
    const baseColumnArr = []
    for (let col of columnList) {
        if (col.name === primaryKey) {
            resultMap.push(`<id column="${col.name}" property="${col.field}"/>`)
        } else {
            resultMap.push(`<result column="${col.name}" property="${col.field}"/>`)
        }
        baseColumnArr.push(`${col.name},`)
    }
    let baseColumn = baseColumnArr.join('\n\t')
    baseColumn = baseColumn.substring(0, baseColumn.length - 1)

    return {
        resultMap: resultMap.join('\n\t'),
        baseColumn,
        insertBatch: getInsertBatch(dbType, afterConvert, baseColumn, prefix, suffix),
        updateBatch: getUpdateBatch(dbType, afterConvert, baseColumn, prefix, suffix)
    }
}
export function getUpdateBatch(dbType, afterConvert, baseColumn, prefix, suffix) {
    const tableName = afterConvert.table.tableName
    const columnList = afterConvert.columnList
    switch (dbType) {
        case 'mysql':
            const mysqlInsertStr = getInsertBatch(dbType, afterConvert, baseColumn, prefix, suffix)
            let mysqlUpdateArr = []
            for(let item of columnList) {
                mysqlUpdateArr.push(`\t${item.name}=values(${item.name})`)
            }
            const mysqlUpdateStr = mysqlUpdateArr.join(',\n')
            return `${mysqlInsertStr}\n\tON DUPLICATE KEY UPDATE\n${mysqlUpdateStr}`
        case 'postgresql':
            const insertStr = getInsertBatch(dbType, afterConvert, baseColumn, prefix, suffix)
            let postgreUpdateArr = []
            for(let item of columnList) {
                postgreUpdateArr.push(`\t${item.name}=excluded.${item.name}`)
            }
            const postgreUpdateStr = postgreUpdateArr.join(',\n')
            return `${insertStr}\n\tON CONFLICT (${afterConvert.table.primaryKey})DO UPDATE SET\n${postgreUpdateStr}`
        case 'oracle':
            let oracleUpdateArr = []
            for (let item of afterConvert.columnList) {
                oracleUpdateArr.push(`${item.name} = #{item.${item.field}`)
            }
            const oracleUpdateStr = oracleUpdateArr.join(',\n')
            return `begin;\n<foreach collection="list" item="item" separator=";">\nupdate ${tableName} set ${oracleUpdateStr}\n</foreach>\ncommit;`
        default:
            return ""
    }
}

export function getInsertBatch(dbType, afterConvert, baseColumn, prefix, suffix) {
    const tableName = afterConvert.table.tableName
    switch (dbType) {
        case 'mysql':
        case 'postgresql':
            return `insert into ${tableName} (${baseColumn}) \n\t value \n\t ${getForeachStrByCols(afterConvert.columnList, prefix,suffix)}`
        case 'oracle':
            let strArr = []
            for (let item of afterConvert.columnList) {
                strArr.push(`#{item.${item.field}}`)
            }
            const str = strArr.join(',\n\t')
            return `begin;\n<foreach collection="list" item="item" separator=";">\ninsert into ${tableName} (${baseColumn})\nvalue\n(\n${str}\n)\n</foreach>\ncommit;`
        default:
            return ""
    }
}

export function getForeachStrByCols(columnList, prefix, suffix) {
    let strArr = []
    for (let item of columnList) {
        strArr.push(`\t\t#{item.${item.field}}`)
    }
    const str = strArr.join(',\n')
    return `${prefix} \n\t\t(\n ${str}\n\t\t) \n \t\t ${suffix}`
}

